#include "StopCriteria.h"

StopCriteria::StopCriteria(void) {
}

StopCriteria::~StopCriteria(void) {
}

void StopCriteria::setOldSolution(vector<double>* solution) {
    this->m_vOldSolution.resize(solution->size());
    for (int i = 0; i < solution->size(); i++) {
        this->m_vOldSolution[i] = (*solution)[i];
    }
}

void StopCriteria::setOldObjFun(double objFun) {
    this->m_nOldObjFun = objFun;
}

bool StopCriteria::checkStop(vector<double> *solution, double objFun, int iter) {
    bool result = false;
    double diffSol = 0;
    double diffObj = 0;
    if (iter < 1) {
        if (solution->size() != m_vOldSolution.size()) {
            setOldSolution(solution);
        }
        setOldObjFun(objFun);

        return false;
    } else {

        for (int i = 0; i < solution->size(); i++) {
            diffSol += abs((*solution)[i] - m_vOldSolution[i]);
        }
        setOldSolution(solution);

        diffObj = abs(objFun - m_nOldObjFun);
        setOldObjFun(objFun);

        cout << "diffSol " << diffSol << " diffObj " << diffObj << "\t";

        if (diffSol < m_nEpsnoSol && diffObj < m_nEpsnoObj) {
            return true;
        }

        if (iter >= this->m_nMaxIter) {
            if (this->m_nMaxIter == 0) {
                return false;
            } else {
                return true;
            }

        }
    }

    return result;
}

bool StopCriteria::checkStop(OptData *optData, double objFun, int iter) {
    if (this->m_vSolutionCoef.size() != optData->getBeamletNumTotal()) {
        this->m_vSolutionCoef.resize(optData->getBeamletNumTotal());

cout<<this->m_vSolutionCoef.size()<<endl;
        for (int indexPoint = 0; indexPoint < optData->getDijTotal()->size(); indexPoint++) {
            for (int indexBeamlet = 0; indexBeamlet < optData->getDijTotal()[indexPoint].size(); indexBeamlet++) {
cout<<indexPoint<<endl;
cout<<optData->getDijTotal()[indexPoint].size()<<endl;
cout<<indexBeamlet<<endl;
cout<< (*optData->getDijTotal())[indexPoint][indexBeamlet]<<endl;
                this->m_vSolutionCoef[indexBeamlet] += (*optData->getDijTotal())[indexPoint][indexBeamlet];
            }
        }
    }

    bool result = false;
    double diffSol = 0;
    double diffObj = 0;
    if (iter < 1) {
cout<<"1"<<endl;
cout<<optData->getWeightTotal()->size() <<endl;
        if (optData->getWeightTotal()->size() != m_vOldSolution.size()) {
            setOldSolution(optData->getWeightTotal());
        }
        setOldObjFun(objFun);

        return false;
    } else {
cout<<"2"<<endl;
        for (int i = 0; i < optData->getWeightTotal()->size(); i++) {
            diffSol += abs((*optData->getWeightTotal())[i] - m_vOldSolution[i]) * m_vSolutionCoef[i];
        }
        diffSol = diffSol / optData->getBeamletNumTotal();
        setOldSolution(optData->getWeightTotal());

        diffObj = abs(objFun - m_nOldObjFun);
        setOldObjFun(objFun);

        cout << "diffSol " << diffSol << " diffObj " << diffObj << "\t";

        if (diffSol < m_nEpsnoSol && diffObj < m_nEpsnoObj) {
            return true;
        }

        if (iter >= this->m_nMaxIter) {
            if (this->m_nMaxIter == 0) {
                return false;
            } else {
                return true;
            }

        }
    }

    return result;
}

double StopCriteria::calculateStepSize(double rho, vector<double> *solution, int iter) {
    if (iter < 1) {
        return 1;
    }

    
    if (m_vOldSolution.size() != solution->size()) {
        setOldSolution(solution);

        return rho;
    }

    double MaxDiff = 0;
    cout<<"2"<<endl;
    for (int i = 0; i < solution->size(); i++) {
        if (MaxDiff < abs((*solution)[i] - m_vOldSolution[i])) {
            MaxDiff = abs((*solution)[i] - m_vOldSolution[i]);
        }
    }

    cout << MaxDiff << "\t";
    if (MaxDiff > 0.02) {
        return 1;
    } else {
        double size = pow(0.99995, m_nDynamic);
        m_nDynamic++;
        if (size > 0.05) {
            return size;
        } else {
            return 0.05;
        }
    }
}